package de.idgard.android.addon.services.transport;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;

import android.content.Context;
import android.os.AsyncTask;

import com.google.web.bindery.requestfactory.shared.RequestTransport;
import com.google.web.bindery.requestfactory.shared.ServerFailure;

import de.idgard.android.R;
import de.idgard.android.addon.services.GlobalServiceRegistry;
import de.idgard.android.addon.ui.services.BrowserUtilityService;
import de.idgard.android.addon.ui.services.PropertiesService;
import de.idgard.android.addon.ui.services.dto.IDGardCookieDTO;
import de.idgard.json.transport.IDGHttpClient;

/**
 * 
 * @author <a href="mailto:vesko.georgiev@uniscon.com">Vesko Georgiev</a>
 */
public class LoginRequestTransport implements RequestTransport {

	private URI uri;
	private IDGHttpClient httpClient;

	private PropertiesService getPropertiesService() {
		return GlobalServiceRegistry.instance().getPropertiesService();
	}

	private BrowserUtilityService getBrowserUtilityService() {
		return GlobalServiceRegistry.instance().getBrowserUtilityService();
	}

	public LoginRequestTransport(Context context) {
		try {
			String domain = getPropertiesService().getString(R.string.system_domain);
			String loginContext = getPropertiesService().getString(R.string.service_login_service);
			this.uri = new URI(loginContext);
			this.httpClient = new IDGHttpClient(domain);
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}

	public void send(final String payload, final TransportReceiver receiver) {
		AsyncRequest ar = new AsyncRequest(receiver);
		ar.execute(payload);
	}

	private String getIDGardCookie(HttpResponse response) {
		String key = getPropertiesService().getString(R.string.idgardidcookie);
		return getFirst(response.getHeaders(key));
	}

	private String getCrossSitePreventionCookie(HttpResponse response) {
		String key = getPropertiesService().getString(R.string.crosssitepreventioncookie);
		String value = getAtPosition(response.getHeaders("Set-Cookie"),  2);
		String[] cookieParts = value.split(";");
		if (cookieParts.length > 1) {
			String cookies = cookieParts[0];
			String[] keyValue = cookies.split("=");

			if (keyValue.length == 2 && key.equals(keyValue[0])) {
				return keyValue[1];
			}
		}
		return null;
	}

	private String getJSessionIdCookie(HttpResponse response) {
		String key = getPropertiesService().getString(R.string.jsessionidcookie);
		String value = getFirst(response.getHeaders("Set-Cookie"));
		String[] cookieParts = value.split(";");
		String cookies = cookieParts[0];
		String[] keyValue = cookies.split("=");

		if (keyValue.length == 2 && key.equals(keyValue[0])) {
			return keyValue[1];
		}
		return null;
	}

	private String getFirst(Header[] headers) {
		return (headers != null && headers.length > 0) ? headers[0].getValue() : null;
	}

	private String getAtPosition(Header[] headers,  int position) {
		return (headers != null && headers.length >= position - 1) ? headers[position - 1].getValue() : null;
	}
	
	/**
	 * Reads an entire input stream as a String. Closes the input stream.
	 */
	public String readStreamAsString(HttpEntity httpEntity) {
		InputStream in = null;
		try {
			in = httpEntity.getContent();
			ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
			byte[] buffer = new byte[1024];
			int count;
			while ((count = in.read(buffer)) > 0) {
				out.write(buffer, 0, count);
			}
			return out.toString("UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("The JVM does not support the compiler's default encoding.", e);
		} catch (IOException e) {
			return null;
		}
		finally {
			try {
				if (in != null) {
					in.close();
				}
			} catch (IOException ignored) {
			}
		}
	}

	private class AsyncRequest extends AsyncTask<String, Void, HttpResponse> {
		TransportReceiver receiver;
		boolean success;
		String content;

		public AsyncRequest(TransportReceiver receiver) {
			this.receiver = receiver;
		}

		@Override
		protected HttpResponse doInBackground(String... params) {
			String payload = params[0];
			HttpPost post = new HttpPost(uri);
			post.setHeader("Referer", getPropertiesService().getString(R.string.system_url));
			post.setHeader("pageurl", getPropertiesService().getString(R.string.system_url));

			try {
				post.setEntity(new StringEntity(payload, "UTF-8"));
				HttpResponse response = httpClient.execute(post);
				if (200 == response.getStatusLine().getStatusCode()) {
					String idgardId = getIDGardCookie(response);
					String jSessionId = getJSessionIdCookie(response);
					String crossSitePreventionCookie = getCrossSitePreventionCookie(response);

					if (idgardId != null && jSessionId != null && crossSitePreventionCookie != null) {
						getBrowserUtilityService().setIDGardData(new IDGardCookieDTO(idgardId, jSessionId, crossSitePreventionCookie));
					}
					content = readStreamAsString(response.getEntity());
					success = true;
				} else {
					content = response.getStatusLine().getReasonPhrase();
					success = false;
				}
			} catch (Exception e) {
				e.printStackTrace();
				content = "No connection with the IDGARD Server";
				success = false;
			}
			return null;
		}

		@Override
		protected void onPostExecute(HttpResponse response) {
			if (success) {
				receiver.onTransportSuccess(content);
			} else {
				receiver.onTransportFailure(new ServerFailure(content));
			}
		}
	}
}
